// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

module ddr5_pwrgd_logic
(
// ------------------------
// Clock and Reset signals
// ------------------------
   input       iClk,                                        //clock for sequential logic 
   input       iRst_n,                                      //reset signal from PLL Lock, resets state machine to initial state
// ----------------------------
// inputs and outputs
// ---------------------------- 
   input       iFM_SLPS4_N,                                 //SLP_S4 indication
	input       iPWRGD_PS_PWROK,                             //PSU PWRGD
	
	input       iDDRIO_PWRGD,                                //DRAMPWRGD for valid DIMM FAIL detection
	input       iMC_RST_N,                                   //Reset from memory controller
	input       iDDR_GLBRST_THERMTRIP_DOWN,
	inout       ioPWRGD_FAIL_CH_DIMM_CPU,                    //PWRGD_FAIL bidirectional signal
	
	output reg  oDIMM_MEM_FLT,                               //MEM Fault
	output      oPWRGD_DRAMPWRGD_OK,                         //DRAM PWR OK
   output      oFPGA_DIMM_RST_N                             //Reset to DIMMs

);

//////////////////////////////////////////////////////////////////////////////////
// States for FSM
//////////////////////////////////////////////////////////////////////////////////
   localparam  ST_INIT                 = 3'd0;
	localparam  ST_PSU                  = 3'd1;
	localparam  ST_DDRIO                = 3'd2;
	localparam  ST_LINK                 = 3'd3;
	localparam  ST_FAULT                = 3'd4;


//////////////////////////////////////////////////////////////////////////////////
// Parameters
//////////////////////////////////////////////////////////////////////////////////
	localparam  LOW  = 1'b0;
	localparam  HIGH = 1'b1;

//////////////////////////////////////////////////////////////////////////////////
// Internal Signals
//////////////////////////////////////////////////////////////////////////////////
   reg [2:0]   rstate;
	
	reg         rPWRGD_FAIL_CH_DIMM_CPU_EN;
	reg         rPWRGD_DRAMPWRGD_OK;
	reg         rFPGA_DIMM_RST_N;


   wire         wPwrGdFail;    //output of the sync for PWRGDFAIL signal
			
//////////////////////////////////////////////////////////////////////////////////
// Combiantional Logic
//////////////////////////////////////////////////////////////////////////////////	
   assign      oPWRGD_DRAMPWRGD_OK			=	rPWRGD_DRAMPWRGD_OK;
	
	assign      ioPWRGD_FAIL_CH_DIMM_CPU   =  rPWRGD_FAIL_CH_DIMM_CPU_EN ? 1'bz : LOW;                                 //Set as open drain only in ST_DDRIO or ST_LINK state
	
	assign      oFPGA_DIMM_RST_N           =  rFPGA_DIMM_RST_N;                                                        //DIMM out of reset MC is high AND pwrgd_fail input is high


//////////////////////////////////////////////////////////////////////////////////
//Synch Logic for PWRGDFAIL

   //3-tab sycn with comparator between tabs 1 and 2 (if the same, then tab 3 captures from tab 2, otherwise, stays the same)
   GlitchFilter2 #
     (
      .NUMBER_OF_SIGNALS (1),
      .RST_VALUE(0)
      ) 
   PWRGDFAIL_GF
     (
      .iClk (iClk),
      .iARst_n(iRst_n),
      .iSRst_n(iDDRIO_PWRGD),
      .iEna(1'b1),
      .iSignal (ioPWRGD_FAIL_CH_DIMM_CPU),
      .oFilteredSignals(wPwrGdFail)
      );
   
//////////////////////////////////////////////////////////////////////////////////
   
	
//////////////////////////////////////////////////////////////////////////////////
// DIMM Control FSM logic
//////////////////////////////////////////////////////////////////////////////////	

   always @ (posedge iClk or negedge iRst_n) begin
	   if(!iRst_n) begin
		   rFPGA_DIMM_RST_N                     <= LOW;
		end
		else begin
		   rFPGA_DIMM_RST_N <= (rPWRGD_DRAMPWRGD_OK && wPwrGdFail) ? iMC_RST_N : LOW;
		end
	end


   always @ (posedge iClk or negedge iRst_n) begin
	   if(!iRst_n) begin
		   rPWRGD_FAIL_CH_DIMM_CPU_EN           <= LOW;                             //FPGA will LOW its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
			rPWRGD_DRAMPWRGD_OK                  <= LOW;
			oDIMM_MEM_FLT                        <= LOW;
			
			rstate                               <= ST_INIT;
		end
		else begin
		   case(rstate)
			   ST_INIT: begin
				   rPWRGD_FAIL_CH_DIMM_CPU_EN     <= LOW;                             //FPGA will LOW its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
					rPWRGD_DRAMPWRGD_OK            <= LOW;
					oDIMM_MEM_FLT                  <= LOW;
					
					if(iPWRGD_PS_PWROK && iFM_SLPS4_N && !iDDR_GLBRST_THERMTRIP_DOWN) begin                           //Condition to start DDR5 PWR sequence
					   rstate                      <= ST_PSU;
					end
				end
				
				ST_PSU: begin
				   rPWRGD_FAIL_CH_DIMM_CPU_EN     <= LOW;                             //FPGA will LOW its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
					rPWRGD_DRAMPWRGD_OK            <= LOW;
					oDIMM_MEM_FLT                  <= LOW;
					
					if(!iPWRGD_PS_PWROK || !iFM_SLPS4_N ||iDDR_GLBRST_THERMTRIP_DOWN) begin                                         //If power down, move to ST_INIT
					   rstate                      <= ST_INIT;
					end
					else if(iPWRGD_PS_PWROK && iDDRIO_PWRGD) begin                     //If DDR PWR RDY, move to ST_DDRIO
					   rstate                      <= ST_DDRIO;
					end
				end
				
				ST_DDRIO: begin
				    rPWRGD_DRAMPWRGD_OK            <= LOW;
					oDIMM_MEM_FLT                  <= LOW;
				    if (iFM_SLPS4_N) begin                             
				       rPWRGD_FAIL_CH_DIMM_CPU_EN     <= HIGH;                            //FPGA will float its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
					end
					else begin
					   if (!rPWRGD_DRAMPWRGD_OK)                                        
					       rPWRGD_FAIL_CH_DIMM_CPU_EN     <= LOW;
					end
					
					if(!iPWRGD_PS_PWROK) begin                                         //If power down, move to ST_INIT
					   rstate                      <= ST_INIT;
					end
					else if ((iPWRGD_PS_PWROK && !iDDRIO_PWRGD)||iDDR_GLBRST_THERMTRIP_DOWN) begin                   //If DDR PWR loss, move to ST_PSU
					   rstate                      <= ST_PSU;
					end
					else if(iPWRGD_PS_PWROK && iDDRIO_PWRGD && wPwrGdFail && iFM_SLPS4_N) begin  //If DDR PWR RDY and PWRGD_FAIL input high, move to ST_LINK
					   rstate                      <= ST_LINK;
					end
				end
				
				ST_LINK: begin
				   rPWRGD_FAIL_CH_DIMM_CPU_EN     <= HIGH;                            //FPGA will float its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
					rPWRGD_DRAMPWRGD_OK            <= HIGH;                            //DRAM PWROK
					oDIMM_MEM_FLT                  <= LOW;
					
					if(!iFM_SLPS4_N && !iPWRGD_PS_PWROK && !wPwrGdFail) begin     //If power down and S5_WITH_12V disabled, move to ST_INIT
					   rstate                      <= ST_INIT;
					end
					else if(!iFM_SLPS4_N ||iDDR_GLBRST_THERMTRIP_DOWN) begin           //If power down and S5_WITH_12V enabled, move to ST_DDRIO
					   rstate                      <= ST_DDRIO;
					end
					else if(iPWRGD_PS_PWROK && (iDDRIO_PWRGD ^ wPwrGdFail)) begin  //If only DDRIO or PMIC drops out of regulation
					   rstate                      <= ST_FAULT;
					end
				end
				
				ST_FAULT: begin
				   rPWRGD_FAIL_CH_DIMM_CPU_EN     <= LOW;                             //FPGA will float its internal pull-down driver (PWRGD_FAIL[n:0] output pin)
					rPWRGD_DRAMPWRGD_OK            <= LOW;                             //DRAM PWROK
					oDIMM_MEM_FLT                  <= HIGH;                            //ERROR Bit assert
					
					rstate                         <= ST_FAULT;                        //The only way to out of this state is power cycle
				end
				
				default: begin
				   rPWRGD_FAIL_CH_DIMM_CPU_EN     <= LOW;                             
					rPWRGD_DRAMPWRGD_OK            <= LOW;
					oDIMM_MEM_FLT                  <= LOW;
					
					rstate                         <= ST_INIT;
				end
				
			endcase
		end
	end



endmodule
